package com.sea.base.ext.global

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.text.Spannable
import android.text.SpannableString
import android.text.TextUtils
import android.text.style.ForegroundColorSpan
import android.util.Log
import android.widget.Toast
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract

const val LOG_TAG = "seaLog"

@JvmOverloads
fun String.log(tag: String = LOG_TAG) {
    logD(tag)
}

@JvmOverloads
fun String.logD(tag: String = LOG_TAG) {
    Log.d(tag, this)
}

@JvmOverloads
fun String.logI(tag: String = LOG_TAG) {
    Log.i(tag, this)
}

@JvmOverloads
fun String.logW(tag: String = LOG_TAG) {
    Log.w(tag, this)
}

@JvmOverloads
fun String.logE(tag: String = LOG_TAG, t: Throwable? = null) {
    Log.e(tag, this, t)
}

/**
 * @param toastText 吐司文案，空表示不吐司
 */
@JvmOverloads
fun CharSequence?.clipboardAndToast(toastText: CharSequence = "已复制到剪切板") {
    if (this.isNullOrEmpty()) {
        return
    }
    val cbm = singleApplication.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    val clipData = ClipData.newPlainText("AppCopy", this)
    cbm.setPrimaryClip(clipData)
    toastText.toast()
}

/**
 * 不需要inline，不然会生成过多的内部类（外部没有内部类，方法额外增加了内部类的都不要inline）
 */
fun CharSequence.toast() {
    postMainSmart {
        Toast.makeText(singleApplication, this, Toast.LENGTH_SHORT).show()
    }
}

/**
 * Debug时toast+log，颜色为黄色
 */
inline fun CharSequence.toastAndLogDebug(secondTag: String = "", check: () -> Boolean = { true }) {
    if (isDebug && check.invoke()) {
        SpannableString(if (secondTag.isEmpty()) this else "${secondTag}:$this")
            .apply {
                setSpan(ForegroundColorSpan(0xffff9900.toInt()), 0, this.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
            }
            .toast()
        this.toString().logE("td:$secondTag")
    }
}

/**
 * 会丢弃小数点，不会崩溃
 */
@JvmOverloads
fun CharSequence?.toSafeInt(defValue: Int = 0): Int {
    return when (this?.trim()) {
        null, "null", "Null", "NULL", "" -> {
            defValue
        }

        else -> {
            try {
                split(".")[0].toInt()
            } catch (e: Exception) {
                e.printStackTrace()
                defValue
            }
        }
    }
}

/**
 * 会丢弃小数点，不会崩溃
 */
@JvmOverloads
fun CharSequence?.toSafeLong(defValue: Long = 0): Long {
    return when (this?.trim()) {
        null, "null", "Null", "NULL", "" -> {
            defValue
        }

        else -> {
            try {
                split(".")[0].toLong()
            } catch (e: Exception) {
                e.printStackTrace()
                defValue
            }
        }
    }
}

/**
 * 不会崩溃
 * @param newScale 精度，直接删掉（方便去掉多余小数）
 */
@JvmOverloads
fun CharSequence?.toSafeDouble(newScale: Int = -1, defValue: Double = 0.0): Double {
    var st = this
    if (st.isNullOrBlank()) {
        return defValue
    }
    when (st) {
        null, "null", "Null", "NULL", "" -> {
            return defValue
        }
    }
    when {
        st.endsWith(".") -> {
            st = "${st}0"
        }

        st.startsWith(".") -> {
            st = "0${st}"
        }
    }
    try {
        if (newScale >= 0) {
            var endIndex = st.indexOf(".")
            if (endIndex >= 0) {
                if (newScale > 0) {
                    endIndex += newScale + 1
                }
                if (endIndex <= st.length) {
                    return st.substring(0, endIndex).toDouble()
                }
            }
        }
        return st.toString().toDouble()
    } catch (e: Exception) {
        e.printStackTrace()
        return defValue
    }
}

/**
 * 开头添加人民币符号
 */
@Suppress("NOTHING_TO_INLINE")
inline fun String.addRmb() = "¥$this"

/**
 * -¥11.11
 */
@Suppress("NOTHING_TO_INLINE")
inline fun String.addSubRmb() = "-¥$this"

/**
 * 是否以http开头
 */
@Suppress("NOTHING_TO_INLINE")
inline fun String?.isHttp() = this?.startsWith("http") ?: false

/**
 * 如果为空则为另一个值
 */
@Suppress("NOTHING_TO_INLINE")
inline infix fun <T : CharSequence?> T?.emptyThen(to: T): T {
    return if (isNullOrEmpty()) to else this
}

/**
 * 从0到index，并且判断不会越界
 */
@Suppress("NOTHING_TO_INLINE")
inline fun String.substringEnd(endIndex: Int): String {
    if (endIndex > this.length) {
        return this
    }
    return this.substring(0, endIndex)
}

/**
 * 如果[check]为true，则抛出异常
 */
inline fun String.throwIf(e: Throwable? = null, check: () -> Boolean) {
    throwIf(this, e, check)
}

inline fun String.throwIfDebug(e: Throwable? = null, check: () -> Boolean = { true }) {
    throwIfDebug(this, e, check)
}

@Suppress("NOTHING_TO_INLINE")
@OptIn(ExperimentalContracts::class)
inline fun CharSequence?.isNotNullNotEmpty(): Boolean {
    contract {
        returns(true) implies (this@isNotNullNotEmpty != null)
    }
    return !this.isNullOrEmpty()
}

/**
 * 超出指定长度加…（解决maxLength无法…的问题）
 * @param newMaxLength 不包括“…”，所以实际长度会+1
 * @param newEllipsize 目前只支持START,MIDDLE,END
 */
fun String.formatToEllipsize(
    newMaxLength: Int,
    newEllipsize: TextUtils.TruncateAt
): String {
    if (this.isEmpty() || newMaxLength <= 0 || this.length <= newMaxLength + 1) {
        return this
    }
    val size2 = newMaxLength / 2
    return when (newEllipsize) {
        TextUtils.TruncateAt.START -> "…${this.substring(this.length - newMaxLength, this.length)}"
        TextUtils.TruncateAt.MIDDLE -> "${this.substring(0, size2)}…${this.substring(this.length - (newMaxLength - size2), this.length)}"
        else -> "${this.substring(0, newMaxLength)}…"
    }
}

val String?.isFemale get() = this == "F" || this == "0"
val String?.isMale get() = this == "M" || this == "1"

/**
 * 跳到外部浏览器
 */
@Suppress("NOTHING_TO_INLINE")
inline fun String.startWebBrowser() {
    try {
        singleApplication.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(this)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
    } catch (e: Throwable) {
        e.printStackTrace()
        "打开浏览器失败".toast()
        throwIfDebug(e)
    }
}

/**
 * 跳到电话页
 */
fun String.startToDial() {
    try {
        singleApplication.startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel:$this")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
    } catch (e: Throwable) {
        e.printStackTrace()
        "打开打电话页失败".toast()
        throwIfDebug(e)
    }
}

val defAuthorFileProviderSt = "${singleApplication.packageName}.base.AuthorProvider"


